package pfq.demo.java;

/**
 * 位移运算
 */
public class ShiftOperation {

    public static void main(String[] args) {
        int a = 1;

        // 左移，就是将对应的二进制值按位向左移动，所以左移几位就是乘以2的几次方，但如果是负数的话就不是了
        System.out.println(a << 1);
        System.out.println(a << 2);

        // 位移运算最大值不能超过32，如果超了32，则先对32取余，再进行位移运算
        // 所以，a << 32 = a << (32%32) 相当于a << 0
        System.out.println(a << 32);
        System.out.println(a << 0);

        // a << = (33%32) = a << 1
        System.out.println(a << 33);
        System.out.println(a << 1);

        System.out.println("--------------------------");
        // View的measureSpec，测量规格，用一个int类型的值表示两种含义的值
        // int是4个字节，也就是32位，高2位表示测量模式，低30位表示测量大小
        // 测量模式：mode & MODE_MASK，因为测量模式只有3种，用十进制表示就是0、1、2，用二进制表示就是00、01、11，所以放到高位就是在后面补30个0
        // 测量大小：size & ~MODE_MASK，把size的后30位都保留下来，当然你会问那高两位不就丢掉了，确实丢掉了，因为要放测量模式，但size的实际大小也不可能那么大，根本用不到高两位
        // 测量规格：测量模式 | 测量大小，(size & ~MODE_MASK) | (mode & MODE_MASK)，两者做个或运算，只要有1结果就是1，也就是把双方的值都保留下来
        final int MODE_SHIFT = 30;
        final int MODE_MASK = 0x3 << MODE_SHIFT;
        final int UNSPECIFIED = 0 << MODE_SHIFT;// 我原以为测量模式的值就是0、1、2，但其实是0、1、2左移30位后的值，所以这3种测量模式不能用十进制表示，只能用二进制表示
        final int EXACTLY = 1 << MODE_SHIFT;
        final int AT_MOST = 2 << MODE_SHIFT;
        System.out.println("MODE_MASK: " + Integer.toBinaryString(MODE_MASK));
        System.out.println("UNSPECIFIED: " + Integer.toBinaryString(UNSPECIFIED) + ", " + UNSPECIFIED);
        System.out.println("EXACTLY: " + Integer.toBinaryString(EXACTLY) + ", " + EXACTLY);
        System.out.println("AT_MOST: " + Integer.toBinaryString(AT_MOST) + ", " + AT_MOST);

        // 看打印结果，直接进行或运算  和  先进行与运算再进行或运算  的结果是一样，那为啥MeasureSpec.makeMeasureSpec()还要先进行与运算呢？
        // 因为MeasureSpec.makeMeasureSpec()中的size和mode是外部传进来的，所以无法保证size只用到了低30位，同理也无法保证mode只用到了高2位，所以要先进行数据清洗，方法就是使用与运算，mode和高两位是1的值进行与运算，size和低30位是1的值进行与运算，计算完的结果再进行或运算即可。
        System.out.println("3dp, AT_MOST: " + Integer.toBinaryString((3 & ~MODE_MASK) | (AT_MOST & MODE_MASK)));
        System.out.println("3dp, AT_MOST: " + Integer.toBinaryString(3 | AT_MOST));
    }

}
